#include "loger.hpp"
#include "asio.hpp"

#include <thread>
#include <vector>

using asio::ip::tcp;
tcp::acceptor listen(asio::io_context& ioc, int port)
{
    return tcp::acceptor(ioc, tcp::endpoint(tcp::v4(), port));
}

tcp::socket accept(tcp::acceptor& ac)
{
    tcp::endpoint peer;
    asio::error_code ec;
    tcp::socket socket = ac.accept(peer, ec);
    if(socket.is_open() == false) {
        sl::loger::error("accept false:{}", ec.value());
        return  socket;
    }

    sl::loger::info("new connection from{}:{}",
        peer.address().to_string(), peer.port());
    return socket;
}


void handle_read(tcp::socket socket)
{
    std::vector<char> data(1024);
    asio::error_code error;
    for (;;) {    
        std::size_t len = socket.read_some(asio::buffer(data), error);
        if(error.value() == 0 && len == 0) {
            sl::loger::info("connection close by peer");
            return;
        }

        if(error) {
            sl::loger::error("connection error : {}|{}",
                error.value(), error.message());
            return;
        }

        sl::loger::info("read data len:{}, error:{}", len, error.value());

        len = socket.write_some(asio::buffer(data, len), error);
        if(error) {
            sl::loger::error("socket write false:{}, {}", error.value(), len);
        }
        data.clear();
    }
}

int main(int argc, char const* argv[])
{
    asio::io_context io_context(1);
    asio::signal_set signals(io_context, SIGINT, SIGTERM);
    signals.async_wait([&](auto, auto){ io_context.stop(); });

    try {
        tcp::acceptor ac = listen(io_context, 9000);

        for (;;) {
            tcp::socket socket = accept(ac);
            if(socket.is_open() == false){
                break;
            }

            std::thread(handle_read, std::move(socket)).detach();
        }
    }
    catch(const std::exception& e) {
        sl::loger::error("error:{}", e.what());
    }

    // io_context.run();
    sl::loger::info("SyraLink listener start");
    return 0;
}
